<template>
  <el-dialog v-model="visible">
    <DynForm
      ref="DynFormRef"
      :form-data="formData"
      :expand="true"
      :form-item-arr="formItemArr"
      :form-item-comp-name-map="formItemCompNameMap"
    ></DynForm>
    <template #footer>
      <el-button data-test="save-btn" type="primary" @click="onSave">
        保存
      </el-button>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
// TODO 待自行删减多余的资源引入, 以及引入typing.d.ts的类型定义
import {
  DynForm,
  DynItemInput,
  DynItemInputNumber,
  DynItemDate,
  DynItemSelect,
  DynItemRadio,
} from '@ui/base-comp'
import type {
  FormItemConfig,
  VueComp,
  DynFormType,
  OptionItem,
} from '@ui/base-comp'
import { removeEmptyField } from '@ui/base-comp'
import { ref } from 'vue'
import type { PersonEdit } from './typing.d.ts'
import type { FormItemRule } from 'element-plus'
import { axiosInstance } from '@/utils/ajax/AjaxUtil'
import { cloneDeep } from 'lodash-unified'
import { watch, toRefs } from 'vue'
import { nextTick } from 'vue'

const props = defineProps<{ initData?: PersonEdit }>()

const visible = defineModel<boolean>('visible', { required: true })

const { initData } = toRefs(props)

const $emits = defineEmits<{
  save: [d?: PersonEdit]
}>()

const formItemCompNameMap = new Map<string, VueComp>()
formItemCompNameMap.set('DynItemInput', DynItemInput)
formItemCompNameMap.set('DynItemInputNumber', DynItemInputNumber)
formItemCompNameMap.set('DynItemDate', DynItemDate)
formItemCompNameMap.set('DynItemSelect', DynItemSelect)
formItemCompNameMap.set('DynItemRadio', DynItemRadio)

const DynFormRef = ref<DynFormType>()
// TODO 待完善表单项配置. 包括但不限于: placeholder属性配置, rules配置优化, 普通项的name属性填充, 完善loadOptionsMethod配置
// formItemArr理论上可以替换为非响应式对象, 请在实践中决定是否替换为非响应式对象
const formItemArr = ref<FormItemConfig[]>([
  {
    classify: 'formItem',
    name: 'DynItemInput',
    clearable: true,
    label: '姓名',
    prop: 'name',
    rules: () => {
      const ret: FormItemRule[] = []
      ret.push({ required: true, trigger: 'change', message: '该项必填' })
      ret.push({
        validator: (_rule, val, callback) => {
          const str = val as string
          if (str.length >= 10) {
            callback('姓名长度必须小于10')
          } else {
            callback()
          }
        },
        trigger: 'change',
      })
      return ret
    },
  },
  {
    classify: 'formItem',
    name: 'DynItemSelect',
    clearable: true,
    label: '性别',
    prop: 'male',
    rules: () => {
      const ret: FormItemRule[] = []
      ret.push({ required: true, trigger: 'change', message: '该项必填' })
      return ret
    },
    loadOptionsMethod: () => {
      // TODO 请补充可选数据
      return new Promise<OptionItem[]>(resolve => {
        window.setTimeout(() => {
          resolve([
            { value: 'male', label: '男' },
            { value: 'female', label: '女' },
          ])
        }, 18000)
      })
    },
  },
  {
    classify: 'formItem',
    name: 'DynItemInputNumber',
    clearable: true,
    label: '年龄',
    prop: 'age',
    rules: () => {
      const ret: FormItemRule[] = []
      ret.push({ required: true, trigger: 'change', message: '该项必填' })
      ret.push({
        validator: (_, val, callback) => {
          const valNum = val as number
          if (valNum < 18) {
            callback(new Error('年龄必须大于18岁'))
          } else {
            callback()
          }
        },
      })
      return ret
    },
    loadOptionsMethod: () => {
      // TODO 请补充可选数据
      return new Promise<OptionItem[]>(resolve => {
        window.setTimeout(() => {
          resolve([
            { value: 'male', label: '男' },
            { value: 'female', label: '女' },
          ])
        }, 18000)
      })
    },
  },
])

// TODO 待完善填充初始值
const formData = ref<PersonEdit>({
  /**
   * 姓名
   */
  name: '',
  /**
   * 性别
   */
  male: '',
})

watch(initData, newInitData => {
  if (newInitData) {
    formData.value = cloneDeep(newInitData)
  } else {
    formData.value = { name: '' }
    nextTick(() => {
      DynFormRef.value?.elFormInstance?.clearValidate()
    })
  }
})
async function doSaveOrEdit(params: PersonEdit) {
  if (typeof formData.value.idx === 'number') {
    await axiosInstance.put('/local-mock-api/Person/edit', params)
    return formData.value
  } else {
    await axiosInstance.post('/local-mock-api/Person/add', params)
  }
}

function onSave() {
  DynFormRef.value?.elFormInstance?.validate(ret => {
    if (ret) {
      const params = cloneDeep(formData.value)
      removeEmptyField(params)

      doSaveOrEdit(params).then(() => {
        $emits('save', params)
        formData.value = { name: '' }
        visible.value = false
      })
    }
  })
}
defineExpose({ DynFormRef })
</script>
<style scoped lang="scss"></style>
